home *** CD-ROM | disk | FTP | other *** search
/ MacGames Sampler / PHT MacGames Bundle.iso / MacSource Folder / Samples from the CD / C and C++ / GIF source / GIFstuff⁄gif2ras.c < prev    next >
C/C++ Source or Header  |  1989-05-25  |  15KB  |  462 lines

  1. /*
  2.  * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
  3.  *
  4.  * Copyright (c) 1988 by Patrick J. Naughton
  5.  *
  6.  * Author: Patrick J. Naughton
  7.  * naughton@wind.sun.com
  8.  *
  9.  * Permission to use, copy, modify, and distribute this software and its
  10.  * documentation for any purpose and without fee is hereby granted,
  11.  * provided that the above copyright notice appear in all copies and that
  12.  * both that copyright notice and this permission notice appear in
  13.  * supporting documentation.
  14.  *
  15.  * This file is provided AS IS with no warranties of any kind.  The author
  16.  * shall have no liability with respect to the infringement of copyrights,
  17.  * trade secrets or any patents by this file or any part thereof.  In no
  18.  * event will the author be liable for any lost revenue or profits or
  19.  * other special, indirect and consequential damages.
  20.  *
  21.  * Comments and additions should be sent to the author:
  22.  *
  23.  *                     Patrick J. Naughton
  24.  *                     Sun Microsystems, Inc.
  25.  *                     2550 Garcia Ave, MS 14-40
  26.  *                     Mountain View, CA 94043
  27.  *                     (415) 336-1080
  28.  *
  29.  * Revision History:
  30.  * 28-Aug-88: Modified by Jef Poskanzer to output PBM instead of Sun raster.
  31.  * 27-Jul-88: Updated to use libpixrect to fix 386i byteswapping problems.
  32.  * 11-Apr-88: Converted to C and changed to write Sun rasterfiles.
  33.  * 19-Jan-88: GIFSLOW.PAS posted to comp.graphics by Jim Briebel,
  34.  *            a Turbo Pascal 4.0 program to painfully slowly display
  35.  *            GIF images on an EGA equipped IBM-PC.
  36.  *
  37.  * Description:
  38.  *   This program takes a Compuserve "Graphics Interchange Format" or "GIF"
  39.  * file as input and writes a file known as a Sun rasterfile.  This datafile
  40.  * can be loaded by the NeWS "readcanvas" operator and is of the same format
  41.  * as the files in /usr/NeWS/smi/*.  Under X11R2 there is a program called
  42.  * xraster to display these files.
  43.  *
  44.  * Portability:
  45.  *   To make this program convert to some image format other than PBM
  46.  * format simply seach for the tag "PBMS:" in the source and
  47.  * replace these simple mechanisms with the appropriate ones for the
  48.  * other output format.  I have marked all (six) PBM Specific pieces
  49.  * of code with this comment.
  50.  *
  51.  * SS: compile with "cc -o gif2ras -O gif2ras.c -lpixrect"
  52.  * PBMS: compile with "cc -o giftopbm -O giftopbm.c libpbm.a
  53.  */
  54.  
  55. #include <stdio.h>
  56. #ifdef notdefSS
  57. #include <pixrect/pixrect_hs.h> /* SS: main Pixrect header file */
  58. #endif notdefSS
  59. #include <sys/types.h>
  60. #include "pbm.h"                /* PBMS: main PBM header file */
  61.  
  62. typedef int boolean;
  63. #define True (1)
  64. #define False (0)
  65.  
  66. #define NEXTSHORT (*ptr++ + (0x100 * *ptr++))
  67. #define NEXTBYTE (*ptr++)
  68. #define IMAGESEP 0x2c
  69. #define INTERLACEMASK 0x40
  70. #define COLORMAPMASK 0x80
  71.  
  72. int BitOffset = 0,              /* Bit Offset of next code */
  73.     XC = 0, YC = 0,             /* Output X and Y coords of current pixel */
  74.     Pass = 0,                   /* Used by output routine if interlaced pic */
  75.     OutCount = 0,               /* Decompressor output 'stack count' */
  76.     RWidth, RHeight,            /* screen dimensions */
  77.     Width, Height,              /* image dimensions */
  78.     LeftOfs, TopOfs,            /* image offset */
  79.     BitsPerPixel,               /* Bits per pixel, read from GIF header */
  80.     ColorMapSize,               /* number of colors */
  81.     CodeSize,                   /* Code size, read from GIF header */
  82.     InitCodeSize,               /* Starting code size, used during Clear */
  83.     Code,                       /* Value returned by ReadCode */
  84.     MaxCode,                    /* limiting value for current code size */
  85.     ClearCode,                  /* GIF clear code */
  86.     EOFCode,                    /* GIF end-of-information code */
  87.     CurCode, OldCode, InCode,   /* Decompressor variables */
  88.     FirstFree,                  /* First free code, generated per GIF spec */
  89.     FreeCode,                   /* Decompressor, next free slot in hash table */
  90.     FinChar,                    /* Decompressor variable */
  91.     BitMask,                    /* AND mask for data size */
  92.     ReadMask;                   /* Code AND mask for current code size */
  93.  
  94. boolean Interlace, HasColormap;
  95.  
  96. #ifdef notdefSS
  97. /* SS: defined in pixrect/pixrect_hs.h */
  98. Pixrect *Output;                /* The Sun Pixrect */
  99. colormap_t Colormap;            /* The Pixrect Colormap */
  100. u_char *Image;                  /* The result array */
  101. #endif notdefSS
  102. /* PBMS: defined in pbm.h */
  103. bit **bits;                     /* The PBM bit array */
  104.  
  105. u_char *RawGIF;                 /* The heap array to hold it, raw */
  106. u_char *Raster;                 /* The raster data stream, unblocked */
  107.  
  108.     /* The hash table used by the decompressor */
  109. int Prefix[4096];
  110. int Suffix[4096];
  111.  
  112.     /* An output array used by the decompressor */
  113. int OutCode[1025];
  114.  
  115.     /* The color map, read from the GIF header */
  116. u_char Red[256], Green[256], Blue[256];
  117.  
  118. char *id = "GIF87a";
  119.  
  120. char *pname;                    /* program name (used for error messages) */
  121.  
  122. void
  123. error(s1, s2)
  124. char *s1, *s2;
  125. {
  126.     fprintf(stderr, s1, pname, s2);
  127.     exit(1);
  128. }
  129.  
  130.  
  131. main(argc, argv)
  132. int argc;
  133. char *argv[];
  134. {
  135. FILE *fp;
  136. char *infname = argv[1];
  137. char *outfname = argv[2];
  138. int filesize;
  139. register u_char ch, ch1;
  140. register u_char *ptr, *ptr1;
  141. register int i;
  142.  
  143.     setbuf(stderr, NULL);
  144.     pname = argv[0];
  145.  
  146.     if (argc < 3)
  147.         error("usage: %s GIFfile rasterfile\n", NULL);
  148.  
  149.     if (!(fp = fopen(infname, "r")))
  150.         error("%s: %s not found.\n", infname);
  151.  
  152.     /* find the size of the file */
  153.  
  154.     fseek(fp, 0L, 2);
  155.     filesize = ftell(fp);
  156.     fseek(fp, 0L, 0);
  157.  
  158.     if (!(ptr = RawGIF = (u_char *) malloc(filesize)))
  159.         error("%s: not enough memory to read gif file.\n", NULL);
  160.  
  161.     if (!(Raster = (u_char *) malloc(filesize)))
  162.         error("%s: not enough memory to read gif file.\n", NULL);
  163.  
  164.     fread(ptr, filesize, 1, fp);
  165.  
  166.     if (strncmp(ptr, id, 6))
  167.         error("%s: %s is not a GIF file.\n", infname);
  168.     ptr += 6;
  169.  
  170. /* Get variables from the GIF screen descriptor */
  171.  
  172.     RWidth = NEXTSHORT;         /* screen dimensions... not used. */
  173.     RHeight = NEXTSHORT;
  174.  
  175.     ch = NEXTBYTE;
  176.     HasColormap = ((ch & COLORMAPMASK) ? True : False);
  177.  
  178.     BitsPerPixel = (ch & 7) + 1;
  179.     ColorMapSize = 1 << BitsPerPixel;
  180.     BitMask = ColorMapSize - 1;
  181.  
  182.     ch = NEXTBYTE;              /* background color... not used. */
  183.  
  184.     if (NEXTBYTE)               /* supposed to be NULL */
  185.         error("%s: %s is a corrupt GIF file.\n", infname);
  186.  
  187. /* Read in global colormap. */
  188.  
  189.     if (HasColormap) {
  190.         fprintf(stderr, "%s is %d bits per pixel, (%d colors).\n",
  191.                 infname, BitsPerPixel, ColorMapSize);
  192.         for (i = 0; i < ColorMapSize; i++) {
  193.             Red[i] = NEXTBYTE;
  194.             Green[i] = NEXTBYTE;
  195.             Blue[i] = NEXTBYTE;
  196.         }
  197.  
  198. #ifdef notdefSS
  199. /* SS: Fill in the Pixrect colormap struct */
  200.         Colormap.type = RMT_EQUAL_RGB;
  201.         Colormap.length = ColorMapSize;
  202.         Colormap.map[0] = Red;
  203.         Colormap.map[1] = Green;
  204.         Colormap.map[2] = Blue;
  205. #endif notdefSS
  206.         /* PBMS: PBM only handles bitmaps.  Reject any pixmaps here. */
  207.         if (BitsPerPixel != 1)
  208.             error("%s: %s has more than one bit per pixel - it's not a bitmap.\n
  209. ", infname);
  210.     }
  211.     else error("%s: %s does not have a colormap.\n", infname);
  212.  
  213.  
  214. /* Check for image seperator */
  215.  
  216.     if (NEXTBYTE != IMAGESEP)
  217.         error("%s: %s is a corrupt GIF file.\n", infname);
  218.  
  219. /* Now read in values from the image descriptor */
  220.  
  221.     LeftOfs = NEXTSHORT;
  222.     TopOfs = NEXTSHORT;
  223.     Width = NEXTSHORT;
  224.     Height = NEXTSHORT;
  225.     Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
  226.  
  227.     fprintf(stderr, "Reading a %d by %d %sinterlaced image...",
  228.         Width, Height, (Interlace) ? "" : "non-");
  229.  
  230.  
  231. /* Note that I ignore the possible existence of a local color map.
  232.  * I'm told there aren't many files around that use them, and the spec
  233.  * says it's defined for future use.  This could lead to an error
  234.  * reading some files.
  235.  */
  236.  
  237. /* Start reading the raster data. First we get the intial code size
  238.  * and compute decompressor constant values, based on this code size.
  239.  */
  240.  
  241.     CodeSize = NEXTBYTE;
  242.     ClearCode = (1 << CodeSize);
  243.     EOFCode = ClearCode + 1;
  244.     FreeCode = FirstFree = ClearCode + 2;
  245.  
  246. /* The GIF spec has it that the code size is the code size used to
  247.  * compute the above values is the code size given in the file, but the
  248.  * code size used in compression/decompression is the code size given in
  249.  * the file plus one. (thus the ++).
  250.  */
  251.  
  252.     CodeSize++;
  253.     InitCodeSize = CodeSize;
  254.     MaxCode = (1 << CodeSize);
  255.     ReadMask = MaxCode - 1;
  256.  
  257. /* Read the raster data.  Here we just transpose it from the GIF array
  258.  * to the Raster array, turning it from a series of blocks into one long
  259.  * data stream, which makes life much easier for ReadCode().
  260.  */
  261.  
  262.     ptr1 = Raster;
  263.     do {
  264.         ch = ch1 = NEXTBYTE;
  265.         while (ch--) *ptr1++ = NEXTBYTE;
  266.     } while(ch1);
  267.  
  268.     free(RawGIF);               /* We're done with the raw data now... */
  269.  
  270.     fprintf(stderr, "done.\n");
  271.     fprintf(stderr, "Decompressing...");
  272.  
  273.  
  274. #ifdef notdefSS
  275. /* SS: Allocate the Sun Pixrect and make "Image" point to the image data. */
  276.     Output = mem_create(Width, Height, 8);
  277.     if (Output == (Pixrect *) NULL)
  278.         error("%s: not enough memory for output data.\n", NULL);
  279.     Image = (u_char *) mpr_d(Output)->md_image;
  280. #endif notdefSS
  281. /* PBMS: Allocate the PBM bit array. */
  282.     bits = pbm_allocarray(Width, Height);
  283.  
  284.  
  285. /* Decompress the file, continuing until you see the GIF EOF code.
  286.  * One obvious enhancement is to add checking for corrupt files here.
  287.  */
  288.  
  289.     Code = ReadCode();
  290.     while (Code != EOFCode) {
  291.  
  292. /* Clear code sets everything back to its initial value, then reads the
  293.  * immediately subsequent code as uncompressed data.
  294.  */
  295.  
  296.         if (Code == ClearCode) {
  297.             CodeSize = InitCodeSize;
  298.             MaxCode = (1 << CodeSize);
  299.             ReadMask = MaxCode - 1;
  300.             FreeCode = FirstFree;
  301.             CurCode = OldCode = Code = ReadCode();
  302.             FinChar = CurCode & BitMask;
  303.             AddToPixel(FinChar);
  304.         }
  305.         else {
  306.  
  307. /* If not a clear code, then must be data: save same as CurCode and InCode */
  308.  
  309.             CurCode = InCode = Code;
  310.  
  311. /* If greater or equal to FreeCode, not in the hash table yet;
  312.  * repeat the last character decoded
  313.  */
  314.  
  315.             if (CurCode >= FreeCode) {
  316.                 CurCode = OldCode;
  317.                 OutCode[OutCount++] = FinChar;
  318.             }
  319.  
  320. /* Unless this code is raw data, pursue the chain pointed to by CurCode
  321.  * through the hash table to its end; each code in the chain puts its
  322.  * associated output code on the output queue.
  323.  */
  324.  
  325.             while (CurCode > BitMask) {
  326.                 OutCode[OutCount++] = Suffix[CurCode];
  327.                 CurCode = Prefix[CurCode];
  328.             }
  329.  
  330. /* The last code in the chain is treated as raw data. */
  331.  
  332.             FinChar = CurCode & BitMask;
  333.             OutCode[OutCount++] = FinChar;
  334.  
  335. /* Now we put the data out to the Output routine.
  336.  * It's been stacked LIFO, so deal with it that way...
  337.  */
  338.  
  339.             for (i = OutCount - 1; i >= 0; i--)
  340.                 AddToPixel(OutCode[i]);
  341.             OutCount = 0;
  342.  
  343. /* Build the hash table on-the-fly. No table is stored in the file. */
  344.  
  345.             Prefix[FreeCode] = OldCode;
  346.             Suffix[FreeCode] = FinChar;
  347.             OldCode = InCode;
  348.  
  349. /* Point to the next slot in the table.  If we exceed the current
  350.  * MaxCode value, increment the code size unless it's already 12.  If it
  351.  * is, do nothing: the next code decompressed better be CLEAR
  352.  */
  353.  
  354.             FreeCode++;
  355.             if (FreeCode >= MaxCode) {
  356.                 if (CodeSize < 12) {
  357.                     CodeSize++;
  358.                     MaxCode *= 2;
  359.                     ReadMask = (1 << CodeSize) - 1;
  360.                 }
  361.             }
  362.         }
  363.         Code = ReadCode();
  364.     }
  365.  
  366.     free(Raster);
  367.  
  368.     fprintf(stderr, "done.\n");
  369.  
  370.     if (!(fp = fopen(outfname, "w")))
  371.         error("%s: can't create %s.\n", outfname);
  372.  
  373. #ifdef notdefSS
  374. /* SS: Pixrect Rasterfile output code. */
  375.     fprintf(stderr, "Writing Sun Rasterfile: %s...", outfname);
  376.     if (pr_dump(Output, fp, &Colormap, RT_STANDARD, 0) == PIX_ERR)
  377.         error("%s: error writing Sun Rasterfile: %s\n", outfname);
  378. #endif notdefSS
  379. /* PBMS: PBM output code. */
  380.     pbm_writepbm(stdout, bits, Width, Height);
  381.  
  382.     fclose(fp);
  383.  
  384.     fprintf(stderr, "done.\n");
  385. }
  386.  
  387.  
  388. /* Fetch the next code from the raster data stream.  The codes can be
  389.  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
  390.  * maintain our location in the Raster array as a BIT Offset.  We compute
  391.  * the byte Offset into the raster array by dividing this by 8, pick up
  392.  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
  393.  * bring the desired code to the bottom, then mask it off and return it.
  394.  */
  395. ReadCode()
  396. {
  397. int RawCode, ByteOffset;
  398.  
  399.     ByteOffset = BitOffset / 8;
  400.     RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
  401.     if (CodeSize >= 8)
  402.         RawCode += (0x10000 * Raster[ByteOffset + 2]);
  403.     RawCode >>= (BitOffset % 8);
  404.     BitOffset += CodeSize;
  405.     return(RawCode & ReadMask);
  406. }
  407.  
  408.  
  409. AddToPixel(Index)
  410. u_char Index;
  411. {
  412. #ifdef notdefSS
  413.     *(Image + YC * Width + XC) = Index;
  414. #endif notdefSS
  415. /* PBMS: Store a pixel. */
  416.     bits[YC][XC] = Index;
  417.  
  418. /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
  419.  
  420.     if (++XC == Width) {
  421.  
  422. /* If a non-interlaced picture, just increment YC to the next scan line.
  423.  * If it's interlaced, deal with the interlace as described in the GIF
  424.  * spec.  Put the decoded scan line out to the screen if we haven't gone
  425.  * past the bottom of it
  426.  */
  427.  
  428.         XC = 0;
  429.         if (!Interlace) YC++;
  430.         else {
  431.             switch (Pass) {
  432.                 case 0:
  433.                     YC += 8;
  434.                     if (YC >= Height) {
  435.                         Pass++;
  436.                         YC = 4;
  437.                     }
  438.                 break;
  439.                 case 1:
  440.                     YC += 8;
  441.                     if (YC >= Height) {
  442.                         Pass++;
  443.                         YC = 2;
  444.                     }
  445.                 break;
  446.                 case 2:
  447.                     YC += 4;
  448.                     if (YC >= Height) {
  449.                         Pass++;
  450.                         YC = 1;
  451.                     }
  452.                 break;
  453.                 case 3:
  454.                     YC += 2;
  455.                 break;
  456.                 default:
  457.                 break;
  458.             }
  459.         }
  460.     }
  461. }
  462.